package com.xinyue.auto.reader.process;

import java.util.List;

import org.dom4j.Element;

import com.xinyue.auto.bean.Query;
import com.xinyue.auto.exception.HqlException;
import com.xinyue.auto.reader.Process;
import com.xinyue.auto.reader.major.FindMajor;
import com.xinyue.auto.reader.util.JavaTypeUtil;
import com.xinyue.auto.reader.util.ReturnTypeUtil;
import com.xinyue.auto.reader.util.SetterUtil;
import com.xinyue.auto.type.Type;
import com.xinyue.auto.util.StringUtil;

public class HqlProcess extends FindMajor implements Type{
	public HqlProcess(Process read) {
		super(read);
	}

	@SuppressWarnings("unchecked")
	@Override
	protected void process() throws Exception {
		Element find = xml.element(finder_);
		if(find != null) {
			//读取query标签
			List<Element> hs = find.elements(hql_);
			
			if(hs != null && hs.size() > 0) {
				try {
					for (Element hql: hs) {
						//读取公共属性
						Query q = commonRead(hql);
						q.setType(hqlType);
						
						//返回值、强制类型转换、是否单个结果集处理
						hqlReturn(hql, q);
						//入参、paramSetter
						hqlParam(hql, q);
						//hql语句
						q.setState(hqlState(hql));
						
						//添加方法至对象
						holder.getEntity().getFinds().add(q);
					}
				} catch (Exception e) {
					throw new HqlException(e.getMessage(), holder.getException());
				}
			}
		}
	}
	
	/**
	 * HQL返回值
	 * @param hql
	 * @param q
	 * @throws FinderException
	 */
	private void hqlReturn(Element hql, Query q) throws Exception {
		String entity = xml.attributeValue(name_);
		
		String type = hql.attributeValue(returnType_);
		if(StringUtil.isNull(type)) {
			throw new Exception("未定义returnType属性或其值为空");
		}
		
		//query类型判断
		if(!q.isQuery() && !"Integer".equals(type)) {
			throw new Exception("当query属性为false时，返回值只能是Integer:" + type);
		}
		
		if(entity.equals(type)) {
			q.setConvert(true);
			q.setOnly(true);
			q.setReturnType(entity);
		}else if(LIST.equals(type)) {
			q.setWarning(true);
			q.setReturnType("List<" + entity + ">");
		}else if(COUNT.equals(type)) {
			q.setConvert(true);
			q.setOnly(true);
			q.setReturnType(LONG_);
		}else {
			String impt = ReturnTypeUtil.validate(type, q);
			if(impt != null) {
				if("Map".equals(impt)) {
					holder.getDaoImpt().add("java.util.Map");
					holder.getDaoImptExt().add("java.util.HashMap");
				}else {
					holder.getDaoImpt().add(impt);
				}
			}
		}
	}
	
	/**
	 * 处理hql查询的入参以及setter
	 * @param hql
	 * @param q
	 */
	@SuppressWarnings("unchecked")
	private void hqlParam(Element hql, Query q) throws Exception {
		List<Element> params = hql.elements(query_param_);

		//方法入参
		String param = "";
		String paramIn = "";
		
		if(params != null && params.size() > 0) {
			String[] setter = new String[params.size()];
			
			for (int i = 0; i < params.size(); i++) {
				String name = params.get(i).attributeValue(name_);
				String type = params.get(i).attributeValue(type_);
				
				//name属性验证
				if(StringUtil.isNull(name)) {
					throw new Exception("query-param标签未定义name属性或其值为空");
				}
				//type属性验证
				if(StringUtil.isNull(type)) {
					throw new Exception("query-param标签未定义type属性或其值为空");
				}else {
					String impt = JavaTypeUtil.validate(type);
					if(impt != null) {
						holder.getDaoImpt().add(impt);
					}
				}
				
				//合并参数
				param += type + " " + name + ", ";
				paramIn += name + ", ";
				//获取setter语句
				setter[i] = SetterUtil.setterHQL(name, type);
			}
			
			q.setParamSetter(setter);
			//参数处理
			param = param.substring(0, param.length() - 2);
			paramIn = paramIn.substring(0, paramIn.length() - 2);
		}
		
		//是否分页处理
		String paging = hql.attributeValue(paging_);
		if("true".equals(paging)) {
			if(param.length() > 0) {
				param += ", ";
				paramIn += ", ";
			}
			param += "int begin, int count";
			paramIn += "begin, count";
			
			q.setPaging(true);
		}
		
		q.setParams(param);
		q.setParamsIn(paramIn);
	}
	
	/**
	 * 处理HQL语句
	 * @param hql
	 * @return
	 * @throws Exception
	 */
	private String hqlState(Element hql) throws Exception {
		Element state = hql.element(state_);
		if(state == null) {
			throw new Exception("未定义state标签");
		}
		
		String ql = state.getTextTrim();
		if(StringUtil.isNull(ql)) {
			throw new Exception("state标签中未定义hql语句或其值为空");
		}
		
		return ql;
	}
}